use crate::config::app_error::{AppError, AppResult};
use crate::extension::index::index::index_builder::IndexBuilder;
use crate::extension::index::index::index_spec_registry::IndexSpecRegistry;
use crate::extension::index::index::index_specs::{DefaultIndexSpecs, IndexSpecs};
use crate::extension::index::index::indexer::{DefaultIndexer, Indexer};
use crate::extension::index::index::query::index_attribute::IndexAttribute;
use crate::extension::index::index::query::index_descriptor::IndexDescriptor;
use crate::extension::index::index::query::index_entry::IndexEntryImpl;
use crate::extension::index::scheme_manager::{build_store_name_prefix, Scheme, SchemeManager};
use halo_model::{ExtensionGVK, ExtensionOperator, GroupVersionKind, GVK};
use log::info;
use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;
use std::sync::RwLock;

/// 类型擦除的索引器工厂
///
/// 现在不再依赖泛型参数，可以处理任意类型的索引器
pub struct IndexerFactory {
    pub key_space_indexer:
        RwLock<HashMap<String, (TypeId, Arc<RefCell<Box<dyn Any + Send + Sync>>>)>>,
    pub scheme_manager: SchemeManager,
    pub index_spec_register: IndexSpecRegistry,
}

impl IndexerFactory {
    pub async fn create_indexer_for<T: ExtensionGVK>(
        &mut self,
        extension_type: String,
        extension_iterator: Vec<T>,
        key_space_indexer: &mut HashMap<String, Arc<RefCell<DefaultIndexer>>>,
    ) -> AppResult<()> {
        let scheme = self.scheme_manager.get_by_type::<T>().await?;

        let key_space = self.index_spec_register.get_key_space(&scheme);

        if key_space_indexer.contains_key(&key_space) {
            return Err(anyhow::anyhow!("Indexer already exists for type: {}", key_space).into());
        }

        if !self.index_spec_register.contains(&scheme) {
            self.index_spec_register.index_for::<T>(&scheme)?;
        }

        let specs = self.index_spec_register.get_index_specs(&scheme)?;
        let vec = specs.get_index_specs()?;
        let mut index_descriptors = Vec::new();
        for index_spec in vec {
            index_descriptors.push(IndexDescriptor::new(index_spec));
        }

        // 获取当前毫秒数
        let now = std::time::SystemTime::now();

        info!(
            "Start building index for type: {}, please wait...",
            key_space
        );
        let builder = IndexBuilder::new(index_descriptors, extension_iterator)?;

        let entry_container = builder.get_index_entries::<IndexEntryImpl<T>>()?;

        let indexer = DefaultIndexer::new::<T>(entry_container)?;
        key_space_indexer.insert(key_space.clone(), Arc::new(RefCell::new(indexer)));

        info!(
            "Index for type: {} built successfully, cost {} ms",
            key_space,
            now.elapsed().unwrap().as_millis()
        );

        Ok(())
    }

    pub fn get_indexer<T: ExtensionGVK>(
        &self,
        gvk: &GroupVersionKind,
        key_space_indexer: &HashMap<String, Arc<RefCell<DefaultIndexer>>>,
    ) -> AppResult<Arc<RefCell<DefaultIndexer>>> {
        let scheme = self.scheme_manager.get(gvk)?;
        let key_space = self.index_spec_register.get_key_space(&scheme);
        match key_space_indexer.get(&key_space) {
            None => Err(anyhow::anyhow!("Indexer not found for type: {}", key_space).into()),
            Some(x) => Ok(Arc::clone(x)),
        }
    }

    pub fn contains(&self, gvk: &GroupVersionKind) -> bool {
        if let Ok(Some(scheme)) = self.scheme_manager.fetch(gvk) {
            let key_space = &self.index_spec_register.get_key_space(&scheme);
            self.key_space_indexer
                .read()
                .unwrap()
                .contains_key(key_space)
        } else {
            false
        }
    }

    pub fn remove_indexer(&mut self, scheme: &Scheme) {
        let key_space = build_store_name_prefix(scheme);
        {
            self.key_space_indexer.write().unwrap().remove(&key_space);
        }
        // Remove index specs from registry
        self.index_spec_register.remove_index_specs(scheme);
    }
}
